﻿#region << 版 本 注 释 >>
/*----------------------------------------------------------------
// Copyright (C) 2021 kingerrobot
// 版权所有。 
//
// 文件名：IRcsLocation
// 文件功能描述：
//
// 创建者：名字 (zzl)
// 时间：2021/12/7 16:25:32
//
// 修改人：
// 时间：
// 修改说明：
// 版本：V1.0.0
//----------------------------------------------------------------*/
#endregion


//using MyBatis.DataMapper.Model.Statements;
using System.Text.RegularExpressions;
using System;
using KingerRobot.MexicoSailunWMS.Spi;
using Microsoft.EntityFrameworkCore.Internal;
using KingerRobot.MexicoSailunMDC.Dao;
using System.Security.Cryptography;
using System.Threading.Tasks;

namespace KingerRobot.MexicoSailunWMS.SpiService;
internal class BRcsLocation : IRcsLocation
{
    private readonly static IProdSku _ProdSku = new BProdSku();
    private readonly static IWcsLocSku _WcsLocSku = new BWcsLocSku();
    public int UpdateLocationAndWcsLocWithSkuId(
       long? skuId,
       long? startLocId = 0,
       long? targetLocId = 0,
       bool isDelTarget = false)
    {
        var prodSku = _ProdSku.GetProdSkuById(skuId);
        if (prodSku == null)
        {
            return 0;
        }
        var materialId = prodSku.MaterialId;
        var mdTime = prodSku.MdTime;
        var location = UpdateLocationHasSku(materialId, mdTime, startLocId, targetLocId);
        var wcsLoc = _WcsLocSku.SetWcsLocSku(targetLocId, skuId, isDelTarget);

        return location & wcsLoc;
    }
    public List<PORcsLocation> GetLocations()
    {
        var db = Db.Default;
        var result = db.RcsLocations
            .ToList();
        return result;
    }

    public List<PORcsLocation> GetAllLocations()
    {
        var db = Db.Default;
        var result = db.RcsLocations
            .Where(t => t.LocEnable == 1
            && t.ErrInHas == 0
            && t.ErrOutEmpty == 0).AsNoTracking()
            .ToList();
        return result;
    }
    public List<PORcsLocation> GetAllInNoTaskLocations()
    {
        var db = Db.Default;
        var result = GetAllLocations()
            .Where(t => t.InEnable == 1 && t.TaskOccupy == 0)
            .ToList();
        return result;
    }

    public List<PORcsLocation> GetAllOutNoTaskLocations()
    {
        var db = Db.Default;
        var result = GetAllLocations()
            .Where(t => t.OutEnable == 1 && t.TaskOccupy == 0)
            .ToList();
        return result;
    }

    public List<PORcsLocation> GetInStockLocations(EnumInStockType enumInStockType) => enumInStockType switch
    {
        EnumInStockType.Warehousing => GetAllInNoTaskLocations().Where(t => t.LocHasSku == 0).ToList(),
        EnumInStockType.ExWarehouse => GetAllOutNoTaskLocations().Where(t => t.LocHasSku == 1).ToList(),
        _ => new List<PORcsLocation>(),
    };

    public List<PORcsLocation> GetNoGoodsLocations() => GetAllInNoTaskLocations().Where(t => t.LocHasSku == 0).ToList();

    public LocationHasBean GetHasSkuLocations()
    {
        var locations = GetAllInNoTaskLocations();
        return new LocationHasBean
        {
            NoGoods = locations.Where(t => t.LocHasSku == 0).ToList(),
            InStock = locations.Where(t => t.LocHasSku == 1).ToList()
        };
    }

    public PORcsLocation GetLocationById(long id)
    {
        var db = Db.Default;
        var result = db.RcsLocations
            .Where(t => t.Id == id)
            .FirstOrDefault();
        return result;
    }
    public int GetLocationTypeById(long id)
    {
        var db = Db.Default;
        var result = db.RcsLocations
            .Where(t => t.Id == id)?.Select(t => t.LocType).FirstOrDefault() ?? 0;
        return result;
    }
    public PORcsLocation GetLocationByCode(string code)
    {
        var db = Db.Default;
        var result = db.RcsLocations
            .Where(t => t.LocCode == code)
            .FirstOrDefault();
        return result;
    }

    public bool HasLocationById(long id) => GetLocationById(id) != null;

    public int ClearLocationHasTask(long locId)
    {
        var db = Db.Default;
        var result = 0;
        var dateTime = System.DateTime.Now;
        var loc = db.RcsLocations.Where(t => t.Id == locId).FirstOrDefault();
        if (loc is not null)
        {
            loc.TaskId = null;
            loc.TaskOccupy = 0;
            loc.LocHasSku = 0;
            loc.UpdateTime = dateTime;
            loc.LocHasSkuTime = null;
            loc.MaterialId = null;
            loc.TaskOccupyTime = null;
            loc.MdTime = null;
            result = db.SaveChanges();
        }
        return result;
    }
    public int UpdateLocationHasSku(long? materialId,
        DateTime? mdTime,
        long? startLocId = 0,
        long? targetLocId = 0)
    {
        var startnum = 1;
        var targetnum = 1;
        if (startLocId != 0)
        {
            startnum = UpdateLocationNoGood(startLocId);
        }

        if (targetLocId != 0)
        {
            targetnum = UpdateLocationHasGood(materialId, targetLocId, mdTime);
        }

        return startnum & targetnum;
    }

    public int UpdateLocationHasGood(long? materialId, long? locId, DateTime? mdTime)
    {
        var db = Db.Default;
        var dateTime = DateTime.Now;
        var result = 0;

        result = db.RcsLocations.Where(t => t.Id == locId)
            .Update(new PORcsLocation
            {
                TaskId = null,
                TaskOccupy = 0,
                LocHasSku = 1,
                LocHasSkuTime = dateTime,
                MaterialId = materialId,
                UpdateTime = dateTime,
                MdTime = mdTime
            });
        return 1;
    }

    public int UpdateInLocationHasGood(long? materialId, long? locId, string productCode)
    {
        var db = Db.Default;
        var dateTime = DateTime.Now;
        var result = 0;

        result = db.RcsLocations.Where(t => t.Id == locId)
            .Update(new PORcsLocation
            {
                TaskId = null,
                TaskOccupy = 0,
                LocHasSku = 1,
                LocHasSkuTime = dateTime,
                MaterialId = materialId,
                UpdateTime = dateTime,
                ProductCode = productCode
            });
        return db.SaveChanges();
    }

    public int UpdateLocationNoGood(long? locId)
    {
        var db = Db.Default;
        var dateTime = System.DateTime.Now;
        var result = 0;
        result = db.RcsLocations.Where(t => t.Id == locId).Update(new PORcsLocation
        {
            TaskId = null,
            TaskOccupy = 0,
            LocHasSku = 0,
            UpdateTime = dateTime,
            LocHasSkuTime = null,
            MaterialId = null,
            TaskOccupyTime = null,
            MdTime = null
        });
        return db.SaveChanges();
    }




    public List<LocationInfo> GetSingleLocation(List<LocationInfo> pORcsLocations)
    {
        var ids = pORcsLocations
             .GroupBy(t => t.GroupId)
             .Select(t => new { GroupId = t.Key, Count = t.Count() })
             .ToList().Where(t => t.Count == 1).Select(t => t.GroupId).ToList();

        var result = pORcsLocations.Where(t => ids.Contains(t.GroupId)).ToList();
        return result;
    }


    public List<LocationInfo> GetDoubleLocation(List<LocationInfo> pORcsLocations)
    {
        var ids = pORcsLocations
        .GroupBy(t => t.GroupId)
        .Select(t => new { GroupId = t.Key, Count = t.Count() })
        .ToList().Where(t => t.Count == 2).Select(t => t.GroupId).ToList();

        var result = pORcsLocations.Where(t => ids.Contains(t.GroupId)).OrderBy(t => t.GroupId).ToList();
        return result;
    }

    public List<PORcsLocation> GetLocationsByLocIds(List<long?> ids)
    {
        var db = Db.Default;

        var result = GetAllLocations().Where(t => ids.Contains(t.Id)).ToList();
        return result;
    }

    public int ClearLocationHasTaskByTaskId(long taskId)
    {
        var db = Db.Default;

        var dateTime = System.DateTime.Now;
        var result = db.RcsLocations
            .Where(t => t.TaskId == taskId)
            .Update(new PORcsLocation
            {
                TaskId = null,
                TaskOccupy = 0,
                LocHasSku = 0,
                UpdateTime = dateTime,
                LocHasSkuTime = null,
                MaterialId = null,
                TaskOccupyTime = null,
                MdTime = null
            });

        return db.SaveChanges();
    }

    public int UpdateLocEnable(long id)
    {
        var db = Db.Default;
        var dateTime = DateTime.Now;
        var result = 0;

        var loc = db.RcsLocations.Where(t => t.Id == id).FirstOrDefault();
        loc.LocEnable = loc.LocEnable == 1 ? 0 : 1;
        loc.UpdateTime = dateTime;
        loc.Remarks = loc.LocEnable == 1 ? "" : $"人工禁用{dateTime}";

        result = db.SaveChanges();
        return result;
    }
    public int UpdateLocUnEnable(long id, int taskNo = 0)
    {
        var db = Db.Default;
        var dateTime = DateTime.Now;
        var result = 0;
        result = db.RcsLocations.Where(t => t.Id == id).Update(new PORcsLocation
        {
            LocEnable = 0,
            UpdateTime = dateTime,
            Remarks = $"手工删除任务{taskNo},{dateTime}"
        });
        return db.SaveChanges();
    }

    public int ChangeLocEnable(LocEnableParam param)
    {

        if (param.Id is null || param.Id <= 0)//Id需大于0
        {
            return -1;
        }


        var db = Db.Default;
        var dateTime = DateTime.Now;
        var query = db.RcsLocations.Where(t => t.Id == param.Id).FirstOrDefault();

        var result = 0;
        if (query.LocEnable == 1)//启用 ——> 禁用
        {
            if (String.IsNullOrWhiteSpace(param.Remarks))//禁用信息不能空
            {
                return -1;
            }
            result = db.RcsLocations.Where(t => t.Id == param.Id).Update(new PORcsLocation
            {
                LocEnable = 0,
                UpdateTime = dateTime,
                Remarks = param.Remarks
            });
        }
        else// 禁用 ——> 启用
        {
            result = db.RcsLocations.Where(t => t.Id == param.Id).Update(new PORcsLocation
            {
                LocEnable = 1,
                UpdateTime = dateTime,
                Remarks = null
            });
        }
        return 1;
    }

    public int UpdateInEnable(long id)
    {
        var db = Db.Default;
        var dateTime = DateTime.Now;

        var loc = db.RcsLocations.Where(t => t.Id == id).FirstOrDefault();
        loc.InEnable = loc.InEnable == 1 ? 0 : 1;
        loc.UpdateTime = dateTime;

        var result = db.SaveChanges();
        return result;
    }

    public int UpdateOutEnable(long id)
    {
        var db = Db.Default;
        var dateTime = DateTime.Now;

        var loc = db.RcsLocations.Where(t => t.Id == id).FirstOrDefault();
        loc.OutEnable = loc.OutEnable == 1 ? 0 : 1;
        loc.UpdateTime = dateTime;

        var result = db.SaveChanges();
        return result;
    }

    public List<PORcsLocation> GetAllDisableLocations()
    {
        var db = Db.Default;
        var result = db.RcsLocations
            .Where(t => t.LocEnable == 0).AsNoTracking()
            .ToList();
        return result;
    }

    public int UpdateLocProductCode(long id, string productCode)
    {
        var db = Db.Default;
        var result = db.RcsLocations
            .Where(t => t.Id == id).Update(new PORcsLocation
            {
                ProductCode = productCode,
                TaskId = null,

                TaskOccupy = 0,
                TaskOccupyTime = null,
                Remarks = $"{productCode}绑定时间[{DateTime.Now}]"
            });
        return db.SaveChanges();
    }

    public int UpdateLocCoord(CoordPara coordPara)
    {
        var db = Db.Default;

        var loc = db.RcsLocations.Where(f => f.Id == coordPara.Id).FirstOrDefault();

        if (loc is null)
        {
            return -1;
        }


        var dateTime = DateTime.Now;
        var result = 0;
        loc.NAxisX = coordPara.X;
        loc.NAxisZ = coordPara.Z;
        loc.NAxisT = coordPara.T;
        loc.AxisX = coordPara.axisX;
        loc.AxisZ = coordPara.axisZ;
        loc.AxisT = coordPara.axisT;
        loc.UpdateTime = dateTime;


        result = db.SaveChanges();
        return result;
    }

    public List<PORcsLocation> GetLocationByType(int type)
    {
        var db = Db.Default;
        var result = db.RcsLocations
            .Where(t => t.LocType == type && t.UseFlag == 1).ToList();
        return result;
    }

    public List<CrnEnableLocationBean> GetCrnEnableLocation()
    {

        var db = Db.Default;
        var result = db.VEquipCrnNode.Select(t => new CrnEnableLocationBean
        {
            CrnId = t.EquipId ?? 0,
            CrnName = t.ShowName,
            ShortLocationCount = t.EmptyCount ?? 0,
            UnableLocationCount = t.unableEmptyCount ?? 0,
        }).ToList();
        return result;

    }
    public long GetWarehouseByLocationID(long locId)
    {
        var db = Db.Default;
        var locEquipId = db.WcsEquipLocHolds.Where(t => t.LocId == locId).FirstOrDefault()?.EquipId ?? 0;
        var result = db.RcsEquipCrns.Where(t => t.Id == locEquipId).FirstOrDefault()?.WarehourseId ?? 0;
        return result;
    }

    public List<LocationBeanV2> GetLocationV2()
    {
        var db = Db.Default;
        var result = db.RcsLocations.Join(db.WcsEquipLocHolds, f => f.Id, s => s.LocId, (f, s) => new
        {
            Locations = f,
            EquipLocs = s,
        }).Join(db.RcsEquipCrns, f => f.EquipLocs.EquipId, s => s.Id, (f, s) => new
        {
            f.EquipLocs,
            f.Locations,
            EquipCrns = s,
        }).Join(db.RcsEquips, f => f.EquipLocs.EquipId, s => s.Id, (f, s) => new
        {

            f.EquipLocs,
            f.Locations,
            f.EquipCrns,
            s.EquipName,
        }).Join(db.RcsEquipWarehouses, f => f.EquipCrns.WarehourseId, s => s.Id, (f, s) => new
        {
            f.EquipLocs,
            f.Locations,
            f.EquipCrns,
            f.EquipName,
            Warehouses = s,
        }).GroupJoin(db.ProdMaterials, f => f.Locations.MaterialId, s => s.Id, (f, s) => new
        {
            f.EquipLocs,
            f.Locations,
            f.EquipCrns,
            f.Warehouses,
            f.EquipName,
            Materials = s,
        }).SelectMany(t => t.Materials.DefaultIfEmpty(), (f, s) => new
        {
            f.EquipLocs,
            f.Locations,
            f.EquipCrns,
            f.Warehouses,
            f.EquipName,
            Materials = s,
        }).Where(t => t.Locations.LocType == (int)EnumLocType.Location)
          .Select(t => new LocationBeanV2
          {
              Id = t.Locations.Id.GetValueOrDefault(),
              Code = t.Locations.LocCode,
              Name = t.Locations.LocName,
              WarehouseName = t.Warehouses.WarehouseName,
              WarehouseId = t.Warehouses.Id,
              X = t.Locations.AxisX.GetValueOrDefault(),
              Y = t.Locations.AxisY.GetValueOrDefault(),
              Z = t.Locations.AxisZ.GetValueOrDefault(),
              T = t.Locations.AxisT.GetValueOrDefault(),
              LocHasSku = t.Locations.LocHasSku ?? 0,
              LocHasSkuTime = t.Locations.LocHasSkuTime,
              LocEnable = t.Locations.LocEnable ?? 0,
              IsLocEnable = t.Locations.LocEnable == 1 ? true : false,
              InEnable = t.Locations.InEnable ?? 0,
              IsInEnable = t.Locations.InEnable == 1 ? true : false,
              ErrInHas = t.Locations.ErrInHas ?? 0,
              LocType = t.Locations.LocType.GetValueOrDefault(),
              OutEnable = t.Locations.OutEnable ?? 0,
              IsOutEnable = t.Locations.OutEnable == 1 ? true : false,
              ErrOutEmpty = t.Locations.ErrOutEmpty ?? 0,
              RelateScore = t.EquipLocs.RelateScore.GetValueOrDefault(),
              Spec = t.Materials == null ? "" : t.Materials.MaterialCode,
              Remarks = t.Locations.Remarks, //禁用信息,
              EquipName = t.EquipName,
          }).Distinct().ToList();
        return result;


    }

    public List<StockPairBean> GetStockPair()
    {
        var db = Db.Default;
        List<StockPairBean> result = new();
        //所有库存
        var stocks = db.RcsLocations.Join(db.WcsLocSkus, f => f.Id, s => s.LocId, (f, s) => new
        {
            f.LocType,
            f.GroupId,
            f.GroupIndex,
            f.MaterialId,
            s.LocId,
        }).Join(db.WcsEquipLocHolds, f => f.LocId, s => s.LocId, (f, s) => new
        {
            f.LocType,
            f.GroupId,
            f.GroupIndex,
            f.MaterialId,
            s.LocId,
            s.EquipId,
        }).Join(db.RcsEquipCrns, f => f.EquipId, s => s.Id, (f, s) => new
        {
            f.LocType,
            f.GroupId,
            f.GroupIndex,
            f.MaterialId,
            f.LocId,
            f.EquipId,
            s.WarehourseId,
        }).Where(t => t.LocType == (int)EnumLocType.Location);

        //.Join(db.RcsEquips, f => f.EquipId, s => s.Id, (f, s) => new {
        //    f.LocType,
        //    f.GroupId,
        //    f.GroupIndex,
        //    f.MaterialId,
        //    f.LocId,
        //    f.EquipId,
        //    f.WarehourseId,
        //    s.EquipName,
        //}).Where(t => t.LocType == (int)EnumLocType.Location);

        //获取所有库存



        var warehouses = db.RcsEquipWarehouses.ToList();

        foreach (var warehouse in warehouses)
        {
            StockPairBean stockPair = new();
            var pari1 = stocks.Where(t => t.WarehourseId == warehouse.Id & t.GroupIndex == 1).ToList();
            var pari2 = stocks.Where(t => t.WarehourseId == warehouse.Id & t.GroupIndex == 2).ToList();
            var pariNum = pari1.Join(pari2, f => f.GroupId, s => s.GroupId, (f, s) => new
            {
                MaterialId1 = f.MaterialId,
                MaterialId2 = s.MaterialId,
            }).Where(t => t.MaterialId1 == t.MaterialId2).Count() * 2;
            var allNUm = stocks.Where(t => t.WarehourseId == warehouse.Id).Count();
            stockPair.PairNum = pariNum;
            stockPair.AllNum = allNUm;
            stockPair.AllNumPercentage = allNUm == 0 ? 0 : Math.Round((double)pariNum / (double)allNUm * 100, 2);
            stockPair.WarehouseName = warehouse.WarehouseName;
            result.Add(stockPair);

        }
        return result;

    }

}
